<script setup lang="ts">
import { useControlWebsocket, useDeviceWebsocket } from '@/hooks'
import { SESSION } from '@/utils/storage'

/**
 * 路由实例
 */
const router = useRouter()

/**
 * 设备 WebSocket 连接 URL
 */
let tabletDataWebsocketUrl = ''

const tabletWsStatus = ref<'CONNECTING' | 'OPEN' | 'CLOSED'>('CLOSED')

// ==================== WebSocket 连接管理 ====================

/**
 * 控制 WebSocket 连接
 */
const { send: sendControlCommand } = useControlWebsocket({
  onMessage: handleControlWebSocketMessage,
})

/**
 * 设备 WebSocket 连接实例管理
 */
const deviceInstances = {
  tablet: null as ReturnType<typeof useDeviceWebsocket> | null,
  eyeTracker: null as ReturnType<typeof useDeviceWebsocket> | null,
  faceMesh: null as ReturnType<typeof useDeviceWebsocket> | null,
}
/**
 * 处理控制 WebSocket 消息
 * @param {any} response - WebSocket 响应数据
 */
function handleControlWebSocketMessage(response: any) {
  if (response?.status === 'success') {
    if (response.data?.device_name === 'tablet' && response.data?.ws_url) {
      tabletDataWebsocketUrl = response.data?.ws_url
      SESSION.set('tablet_ws_url', tabletDataWebsocketUrl)
      connectToTabletDataWebsocket()
    } else if (response.data?.device_name === 'face_mesh' && response.data?.ws_url) {
      deviceInstances.faceMesh = useDeviceWebsocket(response.data.ws_url, {
        deviceName: 'face_mesh',
        connectOnMount: false,
      })
      deviceInstances.faceMesh.open()
    } else if (response.data?.device_name === 'eye_tracker' && response.data?.ws_url) {
      deviceInstances.eyeTracker = useDeviceWebsocket(response.data.ws_url, {
        deviceName: 'eye_tracker',
        connectOnMount: false,
      })
      deviceInstances.eyeTracker.open()
    }
  }
}

/**
 * 连接到平板设备数据websocket
 */
const connectToTabletDataWebsocket = () => {
  const ws_url = tabletDataWebsocketUrl || SESSION.get('tablet_ws_url')
  if (ws_url) {
    tabletWsStatus.value = 'CONNECTING'
    deviceInstances.tablet = useDeviceWebsocket(ws_url, {
      deviceName: 'tablet',
      onMessage: handleDeviceWebSocketMessage,
    })
    deviceInstances.tablet.open()
  }
}

/**
 * 断开平板设备数据websocket
 */
const disconnectFromTabletDataWebsocket = () => {
  if (deviceInstances.tablet) {
    deviceInstances.tablet.close()
    deviceInstances.tablet = null
  }
}

// ==================== 设备控制命令 ====================

/**
 * 发送设备控制命令
 * @param {string} deviceName - 设备名称
 * @param {string} command - 命令类型
 */
const sendDeviceCommand = (deviceName: string, command: 'start_device' | 'stop_device') => {
  sendControlCommand(
    JSON.stringify({
      command,
      device_name: deviceName,
      token: SESSION.get('access_token') || '',
    }),
  )
}

const stopDevicesOnPlayEnd = () => {
  disableEyeTrackerDevice()
  disableFaceMeshDevice()
  deviceInstances.eyeTracker?.close()
  deviceInstances.eyeTracker = null
  deviceInstances.faceMesh?.close()
  deviceInstances.faceMesh = null
}

/**
 * 关闭所有设备
 */
const stopAllDevices = () => {
  disableTabletDevice()
  stopDevicesOnPlayEnd()
}

/**
 * 启用平板设备
 */
const enableTabletDevice = () => sendDeviceCommand('tablet', 'start_device')

/**
 * 禁用平板设备
 */
const disableTabletDevice = () => sendDeviceCommand('tablet', 'stop_device')

/**
 * 启用眼动追踪设备
 */
const enableEyeTrackerDevice = () => sendDeviceCommand('eye_tracker', 'start_device')

/**
 * 禁用眼动追踪设备
 */
const disableEyeTrackerDevice = () => sendDeviceCommand('eye_tracker', 'stop_device')

/**
 * 启用面部网格设备
 */
const enableFaceMeshDevice = () => sendDeviceCommand('face_mesh', 'start_device')

/**
 * 禁用面部网格设备
 */
const disableFaceMeshDevice = () => sendDeviceCommand('face_mesh', 'stop_device')

// ==================== 数据存储管理 ====================

/**
 * 绘制数据存储
 */
const drawingDataStorage = ref<
  Array<{ x: number; y: number; pressure: number; state: string; timestamp: number }>
>([])

/**
 * Canvas绘制上下文
 */
const canvasContext = ref<CanvasRenderingContext2D | null>(null)

/**
 * 当前绘制路径
 */
const currentPath = ref<Array<{ x: number; y: number; pressure: number }>>([])

/**
 * 是否正在绘制
 */
const isDrawing = ref(false)

/**
 * 存储绘制数据点
 * @param {number} x - 设备 X 坐标
 * @param {number} y - 设备 Y 坐标
 * @param {number} pressure - 压感值
 * @param {string} state - 绘制状态
 */
const storeDrawingData = (x: number, y: number, pressure: number, state: string) => {
  // 直接存储绘制数据，不进行复杂的坐标范围计算
  drawingDataStorage.value.push({
    x,
    y,
    pressure,
    state,
    timestamp: Date.now(),
  })
}

/**
 * 清除存储的绘制数据
 */
const clearStoredDrawingData = () => {
  drawingDataStorage.value = []

  // 清除canvas画布
  clearCanvas()
}

// ==================== Canvas 绘制相关 ====================

/**
 * 初始化Canvas
 */
const initializeCanvas = () => {
  if (!canvasElementRef.value) {
    // 如果canvas元素还没有准备好，延迟100ms后重试
    setTimeout(initializeCanvas, 100)
    return
  }

  const canvas = canvasElementRef.value
  const parentContainer = canvas.parentElement

  if (!parentContainer) {
    console.warn('Canvas父容器未找到')
    return
  }

  // 获取父容器的实际内容区域尺寸（排除padding、border等）
  const containerStyles = window.getComputedStyle(parentContainer)
  const paddingLeft = parseFloat(containerStyles.paddingLeft)
  const paddingRight = parseFloat(containerStyles.paddingRight)
  const paddingTop = parseFloat(containerStyles.paddingTop)
  const paddingBottom = parseFloat(containerStyles.paddingBottom)

  const containerRect = parentContainer.getBoundingClientRect()
  const containerWidth = containerRect.width - paddingLeft - paddingRight
  const containerHeight = containerRect.height - paddingTop - paddingBottom

  // 确保尺寸为正数，并设置最小尺寸
  const canvasWidth = Math.max(200, Math.floor(containerWidth))
  const canvasHeight = Math.max(200, Math.floor(containerHeight))

  // 设置canvas的实际像素尺寸
  canvas.width = canvasWidth
  canvas.height = canvasHeight

  // 重置CSS尺寸为100%，让CSS控制显示尺寸
  canvas.style.width = '100%'
  canvas.style.height = '100%'
  canvas.style.maxWidth = '100%'
  canvas.style.maxHeight = '100%'

  const ctx = canvas.getContext('2d')
  if (ctx) {
    canvasContext.value = ctx

    // 设置绘制样式
    ctx.lineCap = 'round'
    ctx.lineJoin = 'round'
    ctx.strokeStyle = '#2563eb'
    ctx.fillStyle = '#2563eb'

    // 清除画布
    ctx.clearRect(0, 0, canvas.width, canvas.height)

    console.log(`Canvas初始化完成: ${canvasWidth}x${canvasHeight}`)
  }
} /**
 * 设备坐标转Canvas坐标（使用固定设备坐标范围）
 * @param {number} deviceX - 设备X坐标
 * @param {number} deviceY - 设备Y坐标
 * @returns {{x: number, y: number}} Canvas坐标
 */
const deviceToCanvasCoordinates = (deviceX: number, deviceY: number) => {
  if (!canvasElementRef.value) {
    return { x: deviceX, y: deviceY }
  }

  const canvas = canvasElementRef.value

  // 设备坐标范围常量
  const TABLET_WIDTH = 30480
  const TABLET_HEIGHT = 20320

  // 直接使用设备的完整坐标范围进行映射
  const canvasX = (deviceX / TABLET_WIDTH) * canvas.width
  const canvasY = (deviceY / TABLET_HEIGHT) * canvas.height

  return {
    x: Math.max(0, Math.min(canvas.width, canvasX)),
    y: Math.max(0, Math.min(canvas.height, canvasY)),
  }
}

/**
 * 在Canvas上绘制
 * @param {number} deviceX - 设备X坐标
 * @param {number} deviceY - 设备Y坐标
 * @param {number} pressure - 压感值
 * @param {string} state - 绘制状态
 */
const drawOnCanvas = (deviceX: number, deviceY: number, pressure: number, state: string) => {
  if (!canvasContext.value || !canvasElementRef.value) return

  const ctx = canvasContext.value
  const { x, y } = deviceToCanvasCoordinates(deviceX, deviceY)

  // 根据压感调整线条粗细 (0.5-5.0)
  const lineWidth = Math.max(0.5, Math.min(5.0, pressure * 8))
  ctx.lineWidth = lineWidth

  switch (state) {
    case 'Down':
      // 开始新的绘制路径
      isDrawing.value = true
      currentPath.value = [{ x: deviceX, y: deviceY, pressure }]
      ctx.beginPath()
      ctx.moveTo(x, y)
      // 绘制起始点
      ctx.fillRect(x - lineWidth / 2, y - lineWidth / 2, lineWidth, lineWidth)
      break

    case 'Move':
      if (isDrawing.value && currentPath.value.length > 0) {
        // 添加到当前路径
        currentPath.value.push({ x: deviceX, y: deviceY, pressure })

        // 绘制到当前点
        ctx.lineTo(x, y)
        ctx.stroke()

        // 更新路径起点
        ctx.beginPath()
        ctx.moveTo(x, y)
      }
      break

    case 'Up':
      if (isDrawing.value) {
        // 结束当前绘制路径
        isDrawing.value = false
        currentPath.value = []
      }
      break

    case 'Hover':
      // 悬停状态不绘制
      break

    default:
      console.warn('未知的绘制状态:', state)
  }
}

/**
 * 清除Canvas画布
 */
const clearCanvas = () => {
  if (!canvasContext.value || !canvasElementRef.value) return

  const canvas = canvasElementRef.value
  canvasContext.value.clearRect(0, 0, canvas.width, canvas.height)

  // 重置绘制状态
  isDrawing.value = false
  currentPath.value = []
}

/**
 * 处理设备 WebSocket 消息
 * @param {any} response - 设备数据响应
 */
const handleDeviceWebSocketMessage = (response: any) => {
  tabletWsStatus.value = 'OPEN'
  // 处理绘制数据
  if (response?.type === 'device_data' && response.data) {
    const { x, y, pressure, state } = response.data

    if (typeof x !== 'number' || typeof y !== 'number' || typeof pressure !== 'number') {
      console.warn('无效坐标数据:', { x, y, pressure })
      return
    }

    // 存储绘制数据
    storeDrawingData(x, y, pressure, state)

    // 在canvas上绘制
    drawOnCanvas(x, y, pressure, state)
  }
}

// ==================== 视频和问卷数据管理 ====================

/**
 * 视频数据类型定义
 */
type VideoDataType = {
  Video_Url: string
  [key: string]: string
}

/**
 * 视频列表数据
 */
const videoDataList = ref<VideoDataType[]>([])

/**
 * 当前视频源 URL
 */
const currentVideoSource = ref('')

/**
 * 当前选中的视频数据
 */
const currentSelectedVideo = ref<VideoDataType | null>(null)

/**
 * 当前问题索引
 */
const currentQuestionIndex = ref(0)

/**
 * 视频元素引用
 */
const videoElementRef = ref<HTMLVideoElement>()

/**
 * Canvas 元素引用
 */
const canvasElementRef = ref<HTMLCanvasElement>()

/**
 * 视频是否播放完成
 */
const isVideoPlaybackCompleted = ref(false)

/**
 * 计算属性：当前视频的所有问题列表
 */
const currentVideoQuestions = computed(() => {
  if (!currentSelectedVideo.value) return []

  const questionsList: string[] = []
  const videoData = currentSelectedVideo.value

  // 动态获取所有问题字段（Question1, Question2, Question3, etc.）
  Object.keys(videoData).forEach((key) => {
    if (key.startsWith('Question') || key.startsWith('Quetsion')) {
      questionsList.push(videoData[key])
    }
  })

  // 按照数字顺序排序
  return questionsList.sort((a, b) => {
    const aKey = Object.keys(videoData).find((k) => videoData[k] === a) || ''
    const bKey = Object.keys(videoData).find((k) => videoData[k] === b) || ''

    const aNum = parseInt(aKey.replace(/[^0-9]/g, '')) || 0
    const bNum = parseInt(bKey.replace(/[^0-9]/g, '')) || 0

    return aNum - bNum
  })
})

/**
 * 计算属性：问题总数
 */
const totalQuestionsCount = computed(() => {
  return currentVideoQuestions.value.length
})

/**
 * 计算属性：是否显示提交按钮（最后一题时显示）
 */
const shouldShowSubmitButton = computed(() => {
  return (
    totalQuestionsCount.value > 0 && currentQuestionIndex.value === totalQuestionsCount.value - 1
  )
})

/**
 * 计算属性：是否显示下一题按钮
 */
const shouldShowNextButton = computed(() => {
  return totalQuestionsCount.value > 0 && currentQuestionIndex.value < totalQuestionsCount.value - 1
})

/**
 * 计算属性：当前问题内容
 */
const currentQuestionContent = computed(() => {
  return currentVideoQuestions.value[currentQuestionIndex.value] || ''
})

// ==================== 视频控制相关 ====================

/**
 * 禁止视频进度条拖动
 * @param {Event} event - 事件对象
 */
const preventVideoSeeking = (event: Event) => {
  event.preventDefault()
  if (videoElementRef.value) {
    videoElementRef.value.currentTime = videoElementRef.value.currentTime
  }
  return false
}

/**
 * 处理视频开始播放
 */
const handleVideoPlayStart = () => {
  enableEyeTrackerDevice()
  enableFaceMeshDevice()
}

/**
 * 处理视频播放结束
 */
const handleVideoPlayEnd = () => {
  isVideoPlaybackCompleted.value = true
  stopAllDevices()
  enableTabletDevice()
}

/**
 * 重置视频播放状态
 */
const resetVideoPlaybackState = () => {
  isVideoPlaybackCompleted.value = false
  if (videoElementRef.value) {
    videoElementRef.value.currentTime = 0
  }
}

// ==================== 数据获取和业务逻辑 ====================

/**
 * 获取视频列表数据
 */
const fetchVideoListData = async () => {
  try {
    const response = await fetch('http://localhost:8000/static/Questionnaire.json')
    if (!response.ok) {
      throw new Error('网络错误')
    }
    const responseData = await response.json()
    videoDataList.value = Object.values(responseData)

    // 随机选择一个视频
    if (videoDataList.value.length > 0) {
      const randomIndex = Math.floor(Math.random() * videoDataList.value.length)
      currentSelectedVideo.value = videoDataList.value[randomIndex]
      currentVideoSource.value = `http://${currentSelectedVideo.value.Video_Url}`

      // 重置问题索引
      currentQuestionIndex.value = 0
    }
  } catch (error) {
    ElMessage.error('获取视频列表失败，请稍后重试')
    console.error('获取视频列表失败:', error)
  }
}

/**
 * 切换到下一个问题
 */
const proceedToNextQuestion = () => {
  if (!isVideoPlaybackCompleted.value) {
    ElMessage.warning('请先观看完视频')
    return
  }

  // 清空当前存储的绘制数据和canvas画布
  clearStoredDrawingData()

  disableTabletDevice()

  // 关闭平板设备数据websocket
  disconnectFromTabletDataWebsocket()

  // 如果还有下一题，则切换到下一题
  if (currentQuestionIndex.value < totalQuestionsCount.value - 1) {
    currentQuestionIndex.value++
    enableTabletDevice()
  }
}

/**
 * 处理输入操作
 */
const handleUserInput = () => {
  if (!isVideoPlaybackCompleted.value) {
    ElMessage.warning('请先观看完视频')
    return
  }

  if (drawingDataStorage.value.length) {
    ElMessage.warning('正在绘制，请稍后再试')
    return
  }

  // 检查是否有问题可以回答
  if (totalQuestionsCount.value === 0) {
    ElMessage.warning('当前视频没有问题需要回答')
    return
  }

  if ((deviceInstances.tablet?.status as any) === 'CONNECTING') {
    ElMessage.info('设备正在连接中，请稍后...')
    return
  }

  if ((deviceInstances.tablet?.status as any) === 'OPEN') {
    ElMessage.info('设备已打开，请开始输入')
    return
  }
}

/**
 * 处理问卷提交
 */
const handleQuestionnaireSubmit = () => {
  // 添加提交前的验证
  if (totalQuestionsCount.value === 0) {
    ElMessage.warning('没有问题需要提交')
    return
  }

  // 清空绘制数据
  clearStoredDrawingData()

  // 关闭所有设备
  stopAllDevices()

  // 关闭平板设备数据websocket
  disconnectFromTabletDataWebsocket()

  router.push('/audioInteractive')
}

// ==================== 工具函数 ====================

/**
 * 数字转中文
 * @param {number} num - 数字
 * @returns {string} 中文数字
 */
const convertNumberToChinese = (num: number) => {
  const chineseNumbersMap = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
  return chineseNumbersMap[num] || num
}

/**
 * 清理所有资源
 */
const cleanupAllResources = () => {
  // 关闭所有设备和websocket
  stopAllDevices()
  disconnectFromTabletDataWebsocket()
}

// ==================== 生命周期钩子 ====================

/**
 * 窗口大小改变处理函数
 */
const handleWindowResize = () => {
  nextTick(() => {
    initializeCanvas()
  })
}

onMounted(() => {
  fetchVideoListData()
  // 初始化canvas
  nextTick(() => {
    initializeCanvas()
  })

  // 监听窗口大小变化，重新初始化canvas
  window.addEventListener('resize', handleWindowResize)
})

onBeforeUnmount(() => {
  cleanupAllResources()
  // 清理resize事件监听器
  window.removeEventListener('resize', handleWindowResize)
})

// 页面刷新时断开websocket连接
window.addEventListener('beforeunload', cleanupAllResources)
</script>

<template>
  <el-row :gutter="48" class="h-full -mr-6">
    <el-col :span="12" class="flex! flex-col items-center justify-center h-full p-4">
      <video
        ref="videoElementRef"
        :src="currentVideoSource"
        controls
        autoplay
        class="max-w-full max-h-full object-contain w-full h-auto"
        controlslist="nodownload noremoteplayback noplaybackrate"
        disablepictureinpicture
        @seeking="preventVideoSeeking"
        @seeked="preventVideoSeeking"
        @play="handleVideoPlayStart"
        @ended="handleVideoPlayEnd"
        @loadstart="resetVideoPlaybackState"
      >
        您的浏览器不支持 video 标签。
      </video>
    </el-col>
    <el-col :span="12" class="h-full overflow-auto pr-6 flex! flex-col">
      <div class="text-brand text-3xl mt-8">
        {{ `问题${convertNumberToChinese(currentQuestionIndex + 1)}：` }}
      </div>
      <div class="text-2xl text-#055a65 mt-4">{{ currentQuestionContent }}</div>
      <div
        class="flex-1 min-h-0 border border-#D1D1D1 mt-4 rounded-lg shadow-lg bg-white p-4"
        style="min-height: 300px"
      >
        <canvas ref="canvasElementRef" />
      </div>
      <div v-if="totalQuestionsCount > 0" class="flex mt-4 gap-4">
        <el-button class="brand-darker-button flex-1 py-5!" @click="handleUserInput">
          {{
            tabletWsStatus === 'CONNECTING'
              ? '连接中...'
              : tabletWsStatus === 'OPEN'
                ? '输入中...'
                : '设备未连接'
          }}
        </el-button>
        <el-button
          v-show="shouldShowNextButton"
          type="primary"
          class="flex-1 py-5!"
          @click="proceedToNextQuestion"
        >
          下一题
        </el-button>
        <el-button
          v-show="shouldShowSubmitButton"
          type="primary"
          class="flex-1 py-5!"
          @click="handleQuestionnaireSubmit"
        >
          提交
        </el-button>
      </div>
    </el-col>
  </el-row>
</template>

<style scoped>
/* 禁用进度条拖拽功能但保持显示 - WebKit */
video::-webkit-media-controls-timeline {
  pointer-events: none !important;
  cursor: default !important;
}

/* 禁用进度条滑块的交互但保持显示 - WebKit */
video::-webkit-media-controls-timeline::-webkit-slider-thumb {
  pointer-events: none !important;
}

/* 隐藏倍速播放按钮 - WebKit */
video::-webkit-media-controls-playback-rate-menu-button {
  display: none !important;
}

/* 隐藏画中画按钮 - WebKit */
video::-webkit-media-controls-picture-in-picture-button {
  display: none !important;
}

/* 确保音量控制按钮可用 - WebKit */
video::-webkit-media-controls-volume-slider-container {
  pointer-events: auto !important;
  display: block !important;
}

video::-webkit-media-controls-mute-button {
  pointer-events: auto !important;
  display: block !important;
}

video::-webkit-media-controls-volume-slider {
  pointer-events: auto !important;
  display: block !important;
}

/* 确保播放按钮和全屏按钮可用 - WebKit */
video::-webkit-media-controls-play-button {
  pointer-events: auto !important;
}

video::-webkit-media-controls-fullscreen-button {
  pointer-events: auto !important;
}

/* Firefox 兼容性 - 禁用进度条交互但保留音量控制 */
video::-moz-range-progress {
  pointer-events: none !important;
}

video::-moz-range-thumb {
  pointer-events: none !important;
}

/* 确保整个控制栏可见 */
video::-webkit-media-controls-panel {
  display: flex !important;
}

video::-webkit-media-controls {
  display: flex !important;
}

/* 视频样式优化 */
video {
  width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
  border-radius: 8px;
  object-fit: contain;
  -webkit-user-drag: none;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}

/* 视频容器样式 */
.el-col:has(video) {
  min-height: 200px;
  padding: 1rem;
  overflow: hidden;
}

/* Canvas 绘制区域样式 */
canvas {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  display: block;
  border: none;
  cursor: crosshair;
  box-sizing: border-box;
}

/* Canvas 容器样式 */
.el-col:has(canvas) {
  position: relative;
}

/* 绘制区域边框和阴影 */
.border.border-\\#D1D1D1 {
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
  display: flex;
  align-items: stretch;
  justify-content: stretch;
}
</style>
